﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using FarseerGames.FarseerPhysics.Factories;
using FarseerGames.FarseerPhysics;
using FarseerGames.FarseerPhysics.Dynamics;
using FarseerGames.FarseerPhysics.Collisions;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using System.Collections;
using FarseerGames.FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework.Input;

namespace CharacterAnimationEditor
{
    public class Context
    {
        public PhysicsSimulator Physics;
        public SpriteBatch Sb;
        public ContentManager Content;
        public float DeltaTime;
        public SpriteFont Font;
        public SpriteFont FontBig;

        public KeyboardState prevKs;
        public MouseState prevMs;
        public KeyboardState ks;
        public MouseState ms;
        public Vector2 mousePos;


        internal Vector2 GetMouseMovement()
        {
            Vector2 prevPos = new Vector2(prevMs.X, prevMs.Y);
            return mousePos - prevPos;
        }
    }


    public class PhysicsBodyPart
    {
        public Body Body { get; set; }
        public Geom Geometry { get; set; }

        public FixedRevoluteJoint FixedJoint;

        public Keys PlaceKey;
        public Keys FixKey;

        Vector2 Position { get; set; }
        float Rotation { get; set; }

        Dictionary<string, Vector2> Attachments { get; set; }

        public PhysicsBodyPart(Context context, Vector2 size, Vector2 position, float mass, Keys placeKey, Keys fixKey)
        {
            Body = BodyFactory.Instance.CreateRectangleBody(context.Physics, size.X, size.Y, mass);
            Body.Position = position;
            //Body.MomentOfInertia *= 10;
            //Body.IsStatic = true;
            
            Geometry = GeomFactory.Instance.CreateRectangleGeom(context.Physics, Body, size.X, size.Y);
            Geometry.CollisionGroup = 1;

            FixedJoint = JointFactory.Instance.CreateFixedRevoluteJoint(context.Physics, Body, position);
            PlaceKey = placeKey;
            FixKey = fixKey;
        }
    }


    public class Ragdoll
    {
        public PhysicsBodyPart Head { get; set; }
        public PhysicsBodyPart Body { get; set; }
        public PhysicsBodyPart ArmLU { get; set; } // left upper
        public PhysicsBodyPart ArmLL { get; set; } // left lower
        public PhysicsBodyPart ArmRU { get; set; } // right upper
        public PhysicsBodyPart ArmRL { get; set; }
        public PhysicsBodyPart LegLU { get; set; } // left upper
        public PhysicsBodyPart LegLL { get; set; } // left lower
        public PhysicsBodyPart LegRU { get; set; } // right upper
        public PhysicsBodyPart LegRL { get; set; }

        public Ragdoll(Context context, Vector2 pos)
        {

            Vector2 rootPos = pos;
            Vector2 headSize = new Vector2(64, 64);
            Vector2 bodySize = new Vector2(64, 128);
            Vector2 armSize = new Vector2(32, 64);
            Vector2 legSize = new Vector2(64, 128);

            //Vector2 headOffset = new Vector2(-headSize.X/2, -64);
            Vector2 headOffset = new Vector2(0, -bodySize.Y / 2 - headSize.Y / 2);
            Vector2 ArmLUOffset = new Vector2(0, 0);
            Vector2 ArmLLOffset = new Vector2(0, armSize.Y);
            Vector2 ArmRUOffset = new Vector2(0, 0);
            Vector2 ArmRLOffset = new Vector2(0, armSize.Y);
            Vector2 LegLUOffset = new Vector2(0, bodySize.Y / 2 + legSize.Y / 2);
            Vector2 LegLLOffset = new Vector2(0, bodySize.Y / 2 + legSize.Y / 2 + legSize.Y);
            Vector2 LegRUOffset = new Vector2(0, bodySize.Y / 2 + legSize.Y / 2);
            Vector2 LegRLOffset = new Vector2(0, bodySize.Y / 2 + legSize.Y / 2 + legSize.Y);

            Body = new PhysicsBodyPart(context, bodySize, rootPos, 50.0f, Keys.W, Keys.U);
            Head = new PhysicsBodyPart(context, headSize, rootPos + headOffset, 10.0f, Keys.D2, Keys.D7);
            ArmLU = new PhysicsBodyPart(context, armSize, rootPos + ArmLUOffset, 10.0f, Keys.D1, Keys.D6);
            ArmLL = new PhysicsBodyPart(context, armSize, rootPos + ArmLLOffset, 10.0f, Keys.Q, Keys.Y);
            ArmRU = new PhysicsBodyPart(context, armSize, rootPos + ArmRUOffset, 10.0f, Keys.D3, Keys.D8);
            ArmRL = new PhysicsBodyPart(context, armSize, rootPos + ArmRLOffset, 10.0f, Keys.E, Keys.I);
            LegLU = new PhysicsBodyPart(context, legSize, rootPos + LegLUOffset, 10.0f, Keys.A, Keys.H);
            LegLL = new PhysicsBodyPart(context, legSize, rootPos + LegLLOffset, 10.0f, Keys.Z, Keys.N);
            LegRU = new PhysicsBodyPart(context, legSize, rootPos + LegRUOffset, 10.0f, Keys.D, Keys.J);
            LegRL = new PhysicsBodyPart(context, legSize, rootPos + LegRLOffset, 10.0f, Keys.C, Keys.M);

            Vector2 headBodyAttach = new Vector2(0, headSize.Y / 2);
            Vector2 bodyHeadAttach = new Vector2(0, -bodySize.Y / 2);
            Vector2 armBodyAttach = new Vector2(0, -armSize.Y / 2);
            Vector2 bodyArmAttach = new Vector2(0, -armSize.Y / 2);
            Vector2 legBodyAttach = new Vector2(0, -legSize.Y / 2);
            Vector2 bodyLegAttach = new Vector2(0, bodySize.Y / 2);
            Vector2 armLUAttach = new Vector2(0, -armSize.Y / 2);
            Vector2 armULAttach = new Vector2(0, armSize.Y / 2);
            Vector2 legLUAttach = new Vector2(0, -legSize.Y / 2);
            Vector2 legULAttach = new Vector2(0, legSize.Y / 2);

            JointFactory.Instance.CreatePinJoint(context.Physics, Head.Body, headBodyAttach, Body.Body, bodyHeadAttach);
            JointFactory.Instance.CreatePinJoint(context.Physics, ArmLU.Body, armBodyAttach, Body.Body, bodyArmAttach);
            JointFactory.Instance.CreatePinJoint(context.Physics, ArmRU.Body, armBodyAttach, Body.Body, bodyArmAttach);
            JointFactory.Instance.CreatePinJoint(context.Physics, LegLU.Body, legBodyAttach, Body.Body, bodyLegAttach);
            JointFactory.Instance.CreatePinJoint(context.Physics, LegRU.Body, legBodyAttach, Body.Body, bodyLegAttach);
            JointFactory.Instance.CreatePinJoint(context.Physics, ArmRU.Body, armULAttach, ArmRL.Body, armLUAttach);
            JointFactory.Instance.CreatePinJoint(context.Physics, ArmLU.Body, armULAttach, ArmLL.Body, armLUAttach);
            JointFactory.Instance.CreatePinJoint(context.Physics, LegRU.Body, legULAttach, LegRL.Body, legLUAttach);
            JointFactory.Instance.CreatePinJoint(context.Physics, LegLU.Body, legULAttach, LegLL.Body, legLUAttach);

            ArmLL.Body.Position = ArmLL.Body.Position + new Vector2( 30, -20);
            ArmLL.FixedJoint.Anchor=ArmLL.Body.Position;
            ArmLU.FixedJoint.Enabled = false;

            ArmRL.Body.Position = ArmRL.Body.Position + new Vector2(-50, -20);
            ArmRL.FixedJoint.Anchor = ArmRL.Body.Position;
            ArmRU.FixedJoint.Enabled = false;

        }

    }

    public class RagdollView
    {
        public Ragdoll MyRagdoll { get; set; }

        public void Draw(Context context)
        {
            Texture2D headTex = context.Content.Load<Texture2D>("Head");
            Texture2D bodyTex = context.Content.Load<Texture2D>("Body");
            Texture2D armTex = context.Content.Load<Texture2D>("Arm");
            Texture2D legTex = context.Content.Load<Texture2D>("Leg");

            Draw(context, headTex, MyRagdoll.Head);
            Draw(context, bodyTex, MyRagdoll.Body);
            Draw(context, armTex, MyRagdoll.ArmLU);
            Draw(context, armTex, MyRagdoll.ArmLL);
            Draw(context, armTex, MyRagdoll.ArmRU);
            Draw(context, armTex, MyRagdoll.ArmRL);
            Draw(context, legTex, MyRagdoll.LegLU);
            Draw(context, legTex, MyRagdoll.LegLL);
            Draw(context, legTex, MyRagdoll.LegRU);
            Draw(context, legTex, MyRagdoll.LegRL);
        }

        private void Draw(Context context, Texture2D tex, PhysicsBodyPart bodyPart)
        {
            context.Sb.Draw(
                tex,
                bodyPart.Body.Position,
                null,
                bodyPart.FixedJoint.Enabled ? Color.White : new Color(Color.White, 0.5f),
                bodyPart.Body.Rotation,
                new Vector2(tex.Width, tex.Height) * 0.5f,
                1.0f,
                SpriteEffects.None,
                0.5f
                );

            //context.Sb.DrawString(
            //    context.Font, 
            //    bodyPart.PlaceKey.ToString() + "/" + bodyPart.FixKey.ToString() + " " + bodyPart.Body.Rotation.ToString(), 
            //    bodyPart.Body.Position, 
            //    Color.Black);
        }

    }
}
